package com.netqin.netconnection;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;

import android.content.Context;
import android.os.Environment;
import android.os.Handler;

import com.netqin.cache.DataCache;
import com.zcl.utils.NqLog;
import com.zcl.utils.NqUtil;
import com.zcl.utils.Value;

/**
 * HTTP网络连接实现
 * 
 * @author MingLi
 * @since 2011-11-10
 */

final class HttpConnection implements Connection {
    private static final String TAG = "HttpConnection";
    private Context mContext;
    private DataCache mDataCache;
    private Handler mHandler;
    private boolean mProgess;

    /**
     * 单例模式
     * 
     * @param context
     * @param dataCache
     *            保存文件用的缓存
     * @return
     */
    static public Connection getInstance(Context context, DataCache dataCache) {
        if (null == s_inst) {
            s_inst = new HttpConnection(context, dataCache);
        }
        return s_inst;
    }

    private HttpConnection(Context context, DataCache dataCache) {
        mContext = context;
        mDataCache = dataCache;
        followRedirects = false;

        // 设置代理信息
        if (null != mContext) {
            proxy = NqUtil.getApnProxy(mContext);
        }

        if (proxy != null) {
            setProxy(proxy);
        }
    }

    public Connection addUrl(String url) {
        iUrl = url;
        return this;
    }

    /**
     * 确定文件类型
     */
    static String getContentType(String ctype) {
        String suffix = "";
        if (ctype != null) {
            String[] ctypeo = ctype.split("/");
            if ((ctypeo.length > 1) && (ctypeo[1] != null)) {
                String[] ctypel = ctypeo[1].split(";");
                suffix = ctypel[0];
            } else
                suffix = ctypeo[0];
        }
        return suffix;
    }

    /**
     * 
     * @param dataCache
     *            保存文件的缓存，如果不指定或为null，则使用初始化实例时的缓存
     * @return
     */
    public String get(DataCache dataCache) {
        if (null == iUrl) {
            return iUrl;
        }
        String strLocalCacheFile = null;// 本地缓存路径
        HttpURLConnection conn = null;
        try {
            if (!NqUtil.getNetworkEnable(mContext)) {
                return null;
            }
            conn = createConnection(new URL(iUrl));
            conn.connect();
            if (HttpURLConnection.HTTP_OK == conn.getResponseCode()) {
                InputStream s = conn.getInputStream();
                String suffix = getContentType(conn.getContentType());
                int l = 0;
                if ((l = conn.getContentLength()) > 0) {
                    // TODO::待存入缓存模块
                    /**
                     * 缓存数据
                     * 
                     * @param stream
                     *            数据流
                     * @param length
                     *            数据流中字节长度
                     * @param url
                     *            与该次缓存相关的url
                     * @return 当前缓存的全路径
                     */
                    DataCache d = dataCache;
                    if (d == null) {
                        d = mDataCache == null ? DataCache.getInstance(mContext) : mDataCache;
                    }
                    if (null != d) {
                        // woo, we can save this
                        if (d.allowCache(l)) {
                            d.setHandler(mHandler);
                            d.progress(mProgess);
                            if (Value.printLog) {
                                NqLog.d("progress", "try to save::" + iUrl + " data length::" + l);
                            }
                            strLocalCacheFile = d.saveData(s, l, iUrl, suffix);
                            d.setHandler(null);// release handler
                            if (Value.printLog) {
                                NqLog.d("Test", "strLocalCacheFile::" + strLocalCacheFile + "datacache::" + d);
                            }
                        }
                    }
                }
                s.close();
            }
        } catch (Exception ee) {
            // Reason::http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html
            if (conn != null) {
                NqUtil.helpHttpKeepAlive(conn);
            }
            ee.printStackTrace();
        } finally {
            if (null != conn)
                conn.disconnect();
        }
        return strLocalCacheFile;
    }

    /**
     * 设置与外界传递消息的handler
     * 
     * @param h
     */
    public void setHandler(Handler h) {
        mHandler = h;
    }

    /**
     * 是否发送进度消息
     * 
     * @param enable
     */
    public void progress(boolean enable) {
        mProgess = enable;
    }

    static String saveAsFile(InputStream urlStream, int length, String urlString) {

        // 附件条件：检查是否有足够的空间
        String localFilePath = null;
        try {
            localFilePath = Environment.getExternalStorageDirectory().getAbsolutePath()
                    + urlString.substring(urlString.lastIndexOf(File.separatorChar));
            File file = new File(localFilePath);
            file.delete();
            file.createNewFile();// 确保文件存在
            FileInputStream fis = new FileInputStream(file);
            fis.close();

            // set it true;otherwise false)
            FileOutputStream fos = new FileOutputStream(file, true);
            byte buf[] = new byte[length];
            do {
                int numread = urlStream.read(buf);
                if (numread <= 0) {
                    break;
                }
                // mCurSize += numread;
                // mHandler.sendEmptyMessageDelayed(this.UPDATE_DOWNLOAD_PROGRESS,
                // 0);
                fos.write(buf, 0, numread);
            } while (true);
            fos.close();
            urlStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return localFilePath;
    }

    public Connection setHeader() {
        return this;
    }

    public Connection setProxy(Proxy p) {
        proxy = p;
        return this;
    }

    public Connection followRedirects(boolean followRedirects) {
        this.followRedirects = followRedirects;
        return this;
    }

    // 内部实现
    // set up connection defaults, and details from request
    private HttpURLConnection createConnection(URL aUrl) throws IOException {

        HttpURLConnection conn = (null == proxy) ? ((HttpURLConnection) aUrl.openConnection()) : ((HttpURLConnection) aUrl
                .openConnection(proxy));
        conn.setRequestMethod(methodTokens[0]);
        conn.setInstanceFollowRedirects(followRedirects); // don't rely on native redirection
        // support
        conn.setConnectTimeout(Value.httpConnectionConnectTimeout);
        conn.setReadTimeout(Value.httpConnectionReadTimeout);
        conn.setRequestProperty("Connection", "close");
        return conn;
    }

    private boolean followRedirects = false;
    private Proxy proxy = null;

    static Connection s_inst;

    @SuppressWarnings("nls")
    private String methodTokens[] = { "GET"/* , "DELETE", "HEAD", "OPTIONS", "POST", "PUT", "TRACE" */};

    private String iUrl;

}